package croe.jdbc.mybatils;

import croe.jdbc.domain.ClassThreadLocal;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.*;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * User: zengzhili
 * Date: 14-8-1
 * Time: 下午1:57
 */
@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class ExecutorPlugin implements Interceptor {

    private final static String END_WIDTH = "-Inline";

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        if (ClassThreadLocal.get() == null)
            return invocation.proceed();
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];

        ResultMap resultMap = new ResultMap.Builder(mappedStatement.getConfiguration(), mappedStatement.getId() + END_WIDTH,
                ClassThreadLocal.get(), new ArrayList<ResultMapping>()).build();
        List<ResultMap> resultMaps = new ArrayList<ResultMap>();
        resultMaps.add(resultMap);

        ParameterMap parameterMap = new ParameterMap.Builder(mappedStatement.getConfiguration(), mappedStatement.getId() + END_WIDTH, Array.class,
                new ArrayList<ParameterMapping>()).build();

        Field resultMapsField = mappedStatement.getClass().getDeclaredField("resultMaps");
        resultMapsField.setAccessible(true);
        resultMapsField.set(mappedStatement, resultMaps);


        Field parameterMapField = mappedStatement.getClass().getDeclaredField("parameterMap");
        parameterMapField.setAccessible(true);
        parameterMapField.set(mappedStatement, parameterMap);

        ClassThreadLocal.remove();
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
